﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using Microsoft.TeamFoundation.Lab.Workflow.Activities;

namespace HybridLab.Workflow.Activities.UI
{
	internal class DeploymentDetailsEx : PropertyErrorManager
	{
		private bool deploymentNeeded;
		private List<DeploymentScript> scripts;
		private HybridLabWizardData wizardData;
		private Regex EnvRegex = new Regex(@"\$\(([^)]+)\)", RegexOptions.Singleline);

		internal DeploymentDetailsEx(HybridLabWizardData wizardData)
		{
			DeploymentNeeded = true;
			this.wizardData = wizardData;
		}

		internal bool TakePostDeploymentSnapshot { get; set; }

		internal string PostDeploymentSnapshotPrefix { get; set; }

        internal bool DeploymentNeeded
        {
            get
            {
                return deploymentNeeded;
            }
            set
            {
                deploymentNeeded = value;
                ValidateScripts();
            }
        }

        internal List<DeploymentScript> Scripts
        {
            get
            {
                return scripts;
            }
            set
            {
                scripts = value;
                ValidateScripts();
            }
        }

		private bool ValidateEnvironmentVariables(string inputString, IDictionary<string, string> environmentVariables, out string invalidMacros)
		{
			MatchCollection matches = EnvRegex.Matches(inputString);
			var invalidVars = new List<string>();
			invalidMacros = null;
			foreach (Match match in matches)
			{
				if (!environmentVariables.Keys.Contains(match.Groups[1].Value))
				{
					invalidVars.Add(match.Groups[0].Value);
				}
			}
			if (invalidVars.Count <= 0)
			{
				return true;
			}
			invalidMacros = invalidVars.Aggregate("", (t, item) => t + "," + item).TrimStart(",".ToCharArray());
			return false;
		}

		private void ValidateScripts()
		{
			if (DeploymentNeeded)
			{
				if ((Scripts == null) || (Scripts.Count == 0))
				{
					SetPropertyError("Scripts", "You must add at least one script");
					return;
				}
				bool environmentVarsExist = false;
				IDictionary<string, string> environmentVariables = null;
				if (((wizardData != null) && (wizardData.EnvironmentDetails != null)) && (wizardData.EnvironmentDetails != null))
				{
					environmentVarsExist = true;
					environmentVariables = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
					environmentVariables.Add("BuildLocation", "");
					Scripts.ForEach(s =>
						{
							var name = "Machine_" + s.Machine;
							if (!environmentVariables.ContainsKey(name))
							{
								environmentVariables.Add(name, "");
							}
						});
				}
				foreach (DeploymentScript script in Scripts)
				{
					string str;
					if (string.IsNullOrEmpty(script.Machine) || string.IsNullOrEmpty(script.Script))
					{
						SetPropertyError("Scripts", "One or more scripts do not have Agent or Script selected");
						return;
					}
					if (environmentVarsExist && !ValidateEnvironmentVariables(script.Script, environmentVariables, out str))
					{
						SetPropertyError("Scripts", string.Format(CultureInfo.CurrentCulture, "Invalid macro: [{0}] in script [{1}]", str, script.Script));
						return;
					}
					if (script.Script.Contains('|'))
					{
						SetPropertyError("Scripts", string.Format(CultureInfo.CurrentCulture, "Reserved char [{0}] in script [{1}]", '|', script.Script));
						return;
					}
				}
			}
			ClearPropertyError("Scripts");
		}
	}
}